#include "com_arcvideo_ibase_power_onvif_OnvifApi.h"
#include "dauproxyapi.h"
#include "vagsdk_util.h"
#include "logger.h"
#include <string>

// JNI 加载时初始化函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_8) != JNI_OK) {
        return JNI_EVERSION;
    }

    int code = DauProxyApi::GetInstance()->Init();
    if (code != 0) {
        PrintLog("初始化 dauproxy 库失败，错误代码=%d\n", code);
        return JNI_ERR;
    }

    JNIHandle::GetInstance()->Init(env);
    return JNI_VERSION_1_8;
}

// JNI 卸载时释放资源函数
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_8) != JNI_OK) {
        return;
    }
    int code = DauProxyApi::GetInstance()->ProxyReleaseLibrary();
    if (code < 0) {
        PrintLog("ProxyReleaseLibrary 返回错误，错误代码=%d\n", code);
    }
}

// JNI 方法：创建设备
JNIEXPORT jstring JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_createDevice
        (JNIEnv *env, jclass clz, jobject serverDevInfoPlus, jboolean singleChannel) {
    // 解析服务器设备信息
    ParseServerDevInfoPlus rs = ParseServerDevInfo(env, serverDevInfoPlus);
    _server_dev_info_plus serverInfo = rs.info;

    char dev_id[256] = {0}; // 初始化为0以避免未定义行为
    int dev_id_len = sizeof(dev_id);

    // 调用创建设备的函数
    int code = DauProxyApi::GetInstance()->ProxyCreateDevice(dev_id, &dev_id_len, &serverInfo, singleChannel);

    if (code < 0) {
        THROW_VAG_EX(env, "Failed to create device");
        return nullptr;
    }

    // 使用 NewStringUTF 转换 dev_id 为 Java 字符串
    return env->NewStringUTF(dev_id);
}

// JNI 方法：添加设备通道信息
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_addDeviceChannelInfoPlus
        (JNIEnv *env, jclass clz, jstring devUUID, jstring channelId, jstring streamId,jint sourceNum,jint mediaChannel) {
    std::string deviceId = ConvertToStdString(env, devUUID);
    std::string channelIdentifier = ConvertToStdString(env, channelId);
    std::string streamIdStr = ConvertToStdString(env, streamId);

    // 打印请求参数
    /*PrintLog("Received request parameters: \n");
    PrintLog("deviceUUID: %s\n", deviceId.c_str());
    PrintLog("channelId: %s\n", channelIdentifier.c_str());
    PrintLog("streamId: %s\n", streamIdStr.c_str());*/

    int code = DauProxyApi::GetInstance()->ProxyAddDeviceChannelInfoPlus(
            const_cast<char *>(deviceId.c_str()),
            const_cast<char *>(channelIdentifier.c_str()),
            const_cast<char *>(streamIdStr.c_str()),sourceNum,mediaChannel
    );

    PrintLog("========= ProxyAddDeviceChannelInfo ======, code=%d\n", code);
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}


// JNI 方法：删除设备通道信息
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_delDeviceChannelInfo
        (JNIEnv *env, jclass clz, jstring devUUID, jstring channelId, jstring streamId) {
    std::string deviceId = ConvertToStdString(env, devUUID);
    std::string channelIdentifier = ConvertToStdString(env, channelId);
    std::string streamIdentifier = ConvertToStdString(env, streamId);

    int code = DauProxyApi::GetInstance()->ProxyDelDeviceChannelInfo(
            const_cast<char *>(deviceId.c_str()),
            const_cast<char *>(channelIdentifier.c_str()),
            const_cast<char *>(streamIdentifier.c_str())
    );

    PrintLog("========= ProxyDelDeviceChannelInfo ======, code=%d\n", code);
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

// JNI 方法：设置通道媒体信息
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_setChannelMediaInfo
        (JNIEnv *env, jclass clz, jstring devUUID, jobject mediainfo) {
    std::string deviceId = ConvertToStdString(env, devUUID);

    // 打印 devUUID 参数
    //PrintLog("Received devUUID: %s\n", deviceId.c_str());

    // 解析 mediainfo 参数
    ParseChannelMediaInfoPlus rs = ParseChannelMediaInfo(env, mediainfo);
    _channel_media_info_plus channelMediaInfoPlus = rs.info;

    // 打印解析后的 channelMediaInfoPlus 字段
    /*PrintLog("Parsed channel media info: \n");
    PrintLog("channel_id: %s\n", channelMediaInfoPlus._channle_id);
    PrintLog("stream_id: %s\n", channelMediaInfoPlus._stream_id);
    PrintLog("address: %s\n", channelMediaInfoPlus._address);
    PrintLog("residue_uri: %s\n", channelMediaInfoPlus._residue_uri);
    PrintLog("stream_type: %d\n", channelMediaInfoPlus._stream_type);
    PrintLog("width: %d\n", channelMediaInfoPlus._width);
    PrintLog("height: %d\n", channelMediaInfoPlus._height);
    PrintLog("fps: %.2f\n", channelMediaInfoPlus._fps);
    PrintLog("bitrate: %d\n", channelMediaInfoPlus._bitrate);
    PrintLog("v_codec: %d\n", channelMediaInfoPlus._v_codec);
    PrintLog("a_codec: %d\n", channelMediaInfoPlus._a_codec);
    PrintLog("sample_rate: %d\n", channelMediaInfoPlus._sample_rate);
    PrintLog("b_PTZ: %d\n", channelMediaInfoPlus._b_PTZ);
    PrintLog("source_num: %lld\n", channelMediaInfoPlus._source_num);*/

    // 调用 ProxySetChannelMediaInfo API
    int code = DauProxyApi::GetInstance()->ProxySetChannelMediaInfo(
            const_cast<char *>(deviceId.c_str()),
            &channelMediaInfoPlus
    );

    PrintLog("========= ProxySetChannelMediaInfo ======, code=%d\n", code);

    return code < 0 ? JNI_FALSE : JNI_TRUE;
}


// JNI 方法：启动服务器
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_startServer
        (JNIEnv *env, jclass clz, jstring devUUID) {
    std::string deviceId = ConvertToStdString(env, devUUID);
    int code = DauProxyApi::GetInstance()->ProxyStartServer(
            const_cast<char *>(deviceId.c_str())
    );
    PrintLog("========= ProxyStartServer ======, code=%d\n", code);
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

// JNI 方法：销毁设备
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_destroyDevice
        (JNIEnv *env, jclass clz, jstring devUUID) {
    std::string deviceId = ConvertToStdString(env, devUUID);
    int code = DauProxyApi::GetInstance()->ProxyDestroyDevice(
            const_cast<char *>(deviceId.c_str())
    );
    PrintLog("========= ProxyDestroyDevice ======, code=%d\n", code);
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_setChannelName
        (JNIEnv *env, jclass clz, jstring devUUID, jstring channelId, jstring channelName) {
    std::string deviceId = ConvertToStdString(env, devUUID);
    std::string channelIdentifier = ConvertToStdString(env, channelId);
    std::string streamIdentifier = ConvertToStdString(env, channelName);
    int code = DauProxyApi::GetInstance()->ProxySetChannelName(
            const_cast<char *>(deviceId.c_str()),
            const_cast<char *>(channelIdentifier.c_str()),
            const_cast<char *>(streamIdentifier.c_str())
    );
    PrintLog("========= ProxySetChannelName ======, code=%d\n", code);
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

//PTZ回调
void ptzCallBack(_PTZ_param_DAU* param, int type, _PTZ_RESPONSE_DAU* res, void* usrPtr) {
    // 一收到 type 就打印
    printf("ptzCallBack received type: %d\n", type);

    JNIHandle *h = JNIHandle::GetInstance();
    JNIEnv *env;
    h->jvm->AttachCurrentThread((void **) (&env), nullptr);

    // 对于 2,3,61,62,63 类型走原来的 Java 流程
    if (type == 2 || type == 3 || type == 61 || type == 62 || type == 63) {
        jobject ptzParam = ConvertsPtzParam(env, param);  // 仅这些 type 执行
        jint ptzType = type;
        jobject ptzRes = env->CallStaticObjectMethod(h->cls_onvifApi, h->mid_onvifApi_ptzCallBackFun, ptzParam, ptzType);
        ParsePtzResponse(env, ptzRes, res);
    }
        // 对于 37,64,65,66 类型，直接生成响应，不用 ConvertsPtzParam
    else if (type == 37 || type == 64 || type == 65 || type == 66) {
        jobject ptzRes = env->CallStaticObjectMethod(h->cls_onvifApi, h->mid_onvifApi_ptzCallBackFun, nullptr, type);
        ParsePtzResponse(env, ptzRes, res);
    }
        // 其他 type
    else {
        printf("ptzCallBack unhandled type: %d\n", type);
    }

    h->jvm->DetachCurrentThread();
}
// 处理回调响应的函数，根据不同类型进行不同处理
void handleCallbackResponse(JNIEnv* env, jobject res, int type, void* _Rec_reserve_info) {
    // 根据回调类型处理响应数据
    switch (type) {
        case REC_IN_GetRecordingSearchResults:
            // type 为 2 时处理返回的 RecSearchInfo
            convertToRecSearchInfo(env, res, _Rec_reserve_info);
            break;

        case REC_IN_GetEventSearchResults:
            // type 为 3 时处理事件查询返回的 RecSearchEventInfo
            ConvertsRecSearchEventInfo(env, res, _Rec_reserve_info);
            break;

        case REC_IN_GetReplayUri:
            // type 为 4 时，处理 URL 返回值
            // 可以根据需求进一步处理 URL 返回值
            ConvertsRecUrlInfo(env, res, _Rec_reserve_info);
            break;

        default:
            // 对于其他类型的返回值，不需要处理，直接跳过
            break;
    }
}
// 处理回调的函数
void recordCallBack(_Rec_Info_DAU* info, int type, void* _Rec_reserve_info, void* usrPtr) {
    // 获取全局 JNI 句柄实例
    JNIHandle* h = JNIHandle::GetInstance();
    JNIEnv* env;

    // 将当前线程附加到 JVM，允许使用 JNI
    h->jvm->AttachCurrentThread((void**)(&env), nullptr);

    // 将 Rec_Info_DAU 转换为 Java 对象
    jobject recInfo = ConvertsRecInfoDAU(env, info);  // 假设存在 ConvertsRecInfoDAU 函数

    // 记录传入的类型，便于后续处理
    jint recType = type;

    // 初始化 Java 对象
    jobject recRecSearchInfo = nullptr;
    jobject recSearchEventInfo = nullptr;

    // 根据不同的 type 类型，处理不同的转换逻辑
    switch (type) {
        case REC_IN_GetRecordingSearchResults:
            // type 为 2 时处理 RecSearchInfo 转换
            recRecSearchInfo = ConvertsRecSearchInfo(env, _Rec_reserve_info);
            break;

        case REC_IN_GetEventSearchResults:
            // type 为 3 时处理 RecSearchEventInfo 转换
            recSearchEventInfo = ConvertsRecSearchEventInfo(env, _Rec_reserve_info);
            break;

        case REC_IN_GetReplayUri:
            // type 为 4 时处理 URL 返回值（此处可以根据需要扩展）
            // TODO: 处理获取 Replay URI 的逻辑
            break;

        default:
            // 不支持的类型，提前退出，避免不必要的操作
            h->jvm->DetachCurrentThread(); // 分离线程
            return;
    }

    // 调用 Java 静态方法进行回调，将转换后的数据传递给 Java 层
    jobject res = env->CallStaticObjectMethod(
            h->cls_recordCallbackServiceImpl,   // 回调的 Java 类
            h->mid_recordCallBack,              // 回调的方法 ID
            recInfo,                            // recInfo 对象
            recType,                            // 事件类型
            recRecSearchInfo,                   // RecSearchInfo 对象（可能为空）
            recSearchEventInfo                  // RecSearchEventInfo 对象（可能为空）
    );

    // 根据返回的结果处理不同类型的回调响应
    handleCallbackResponse(env, res, type, _Rec_reserve_info);

    // 从 JVM 中分离当前线程
    h->jvm->DetachCurrentThread();
}
//设置PTZ回调
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_registerPTZCB
  (JNIEnv *env, jclass clz, jstring devUUID) {
    std::string sdevUUID = ConvertToStdString(env, devUUID);
    int code = DauProxyApi::GetInstance()->ProxyRegisterPTZCB((char*)sdevUUID.c_str(), ptzCallBack, nullptr);
    if (code < 0) {
        THROW_VAG_EX(env, "ProxyRegisterPTZCB return error");
        return false;
    }
    return true;
}
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_registerRecordCallback
        (JNIEnv *env, jclass clz, jstring devUUID) {
    std::string sdevUUID = ConvertToStdString(env, devUUID);
    int code = DauProxyApi::GetInstance()->ProxyRegisterRecCB((char*)sdevUUID.c_str(), recordCallBack, nullptr);
    if (code < 0) {
        THROW_VAG_EX(env, "ProxyRegisterRecordCallback return error");
        return false;
    }
    return true;
}
/**
 * 修改录制通道信息
 */
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_modifyRecChannelInfo
        (JNIEnv *env, jclass clz, jstring devId, jstring channelId, jstring streamId, jint recSourceNum, jint channelNum, jboolean hasRec) {

    // 使用公共方法将 jstring 转换为 std::string
    std::string deviceId = ConvertToStdString(env, devId);
    std::string channelIdentifier = ConvertToStdString(env, channelId);
    std::string streamIdStr = ConvertToStdString(env, streamId);

    // 调用 C++ 函数修改录制通道信息
    int code = DauProxyApi::GetInstance()->ProxyModifyRecChannelInfo(
            const_cast<char *>(deviceId.c_str()),
            const_cast<char *>(channelIdentifier.c_str()),
            const_cast<char *>(streamIdStr.c_str()),
            recSourceNum,
            channelNum,
            hasRec
    );
    PrintLog("========= ProxyModifyRecChannelInfo ======, code=%d\n", code);

    // 返回操作结果
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

/**
 * 启停设备发现功能
 */
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_modifyDeviceDiscover
        (JNIEnv *env, jclass clz, jstring devId, jboolean openDiscover) {

    // 使用公共方法将 jstring 转换为 std::string
    std::string deviceId = ConvertToStdString(env, devId);

    // 调用 C++ 函数修改设备发现功能
    int code = DauProxyApi::GetInstance()->ProxyModifyDeviceDescover(
            const_cast<char *>(deviceId.c_str()),
            openDiscover
    );
    PrintLog("========= ProxyModifyDeviceDiscover ======, code=%d\n", code);

    // 返回操作结果
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}

/**
 * 修改设备信息
 */
JNIEXPORT jboolean JNICALL Java_com_arcvideo_ibase_power_onvif_OnvifApi_modifyDeviceInfo
        (JNIEnv *env, jclass clz, jstring devId, jobject serverDevInfoPlus) {

    // 使用公共方法将 jstring 转换为 std::string
    std::string deviceId = ConvertToStdString(env, devId);

    // 解析设备信息
    ParseServerDevInfoPlus rs = ParseServerDevInfoUpdate(env, serverDevInfoPlus);
    _server_dev_info_plus serverInfo = rs.info;

    // 调用 C++ 函数修改设备信息
    int code = DauProxyApi::GetInstance()->ProxyModifyDeviceInfo(
            const_cast<char *>(deviceId.c_str()),
            &serverInfo
    );

    // 打印返回结果日志
    PrintLog("========= ProxyModifyDeviceInfo ======, code=%d\n", code);

    // 返回操作结果
    return code < 0 ? JNI_FALSE : JNI_TRUE;
}





